package com.acegear.horizon.controllers;

import com.acegear.horizon.controllers.vo.ResultVO;
import com.acegear.horizon.domain.models.Club;
import com.acegear.horizon.domain.models.User;
import com.acegear.horizon.domain.models.jpa.ClubMember;
import com.acegear.horizon.domain.repository.ClubRepository;
import com.acegear.horizon.domain.repository.UserRepository;
import com.acegear.horizon.domain.repository.jpa.ClubMemberRepository;
import com.acegear.horizon.domain.services.UserService;

import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;

import java.util.*;


/**
 * Created by mercury on 2016/12/19.
 */
@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserService userService;
    @Autowired
    private ClubRepository clubRepository;
    @Autowired
    private ClubMemberRepository clubMenber;

    @RequestMapping(value = "/{userId}", method = RequestMethod.GET)
    public ResultVO getUserInfo(@PathVariable Long userId) {
        return userRepository
                .findByUserId(userId)
                .map(User::getUserInfo)
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}", method = RequestMethod.PUT)
    @Transactional
    public ResultVO updateUserInfo(@PathVariable Long userId,
                                   @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId,
                                   String nickname, String avatar, Integer gender, String province, String title) {
        if (Objects.equals(userId, viewerId)) {
            return userRepository
                    .findByUserId(userId)
                    .map(user -> user.updateUserInfo(nickname, avatar, gender, province, title))
                    .map(ResultVO::new)
                    .orElse(ResultVO.USER_NOT_FOUND);
        } else {
            return ResultVO.FORBIDDEN;
        }
    }

    @RequestMapping(value = "/{userId}/profile", method = RequestMethod.GET)
    public ResultVO userProfile(@PathVariable Long userId,
                                @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        return userRepository
                .findByUserId(userId)
                .map(user -> user.getProfileVO(viewerId))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{followeeId}/follow", method = RequestMethod.POST)
    public ResultVO follow(@PathVariable Long followeeId,
                           @RequestHeader(value = "X-Consumer-Username", required = false) Long followerId) {
        Map<String, Boolean> result = new HashMap<>();
        if (userRepository
                .findByUserId(followeeId)
                .map(user -> user.follow(followerId))
                .orElse(false)) {
            result.put("success", true);
            return new ResultVO<>(result);
        } else {
            return ResultVO.FOLLOW_ERROR;
        }
    }

    @RequestMapping(value = "/{followeeId}/follow", method = RequestMethod.DELETE)
    @Transactional
    public ResultVO unFollow(@PathVariable Long followeeId,
                             @RequestHeader(value = "X-Consumer-Username", required = false) Long followerId) {
        Map<String, Boolean> result = new HashMap<>();
        if (userRepository
                .findByUserId(followeeId)
                .map(user -> user.unFollow(followerId))
                .orElse(false)) {
            result.put("success", true);
            return new ResultVO<>(result);
        } else {
            return ResultVO.UNFOLLOW_ERROR;
        }
    }

    @RequestMapping(value = "/{userId}/followers", method = RequestMethod.GET)
    public ResultVO getFollowers(@PathVariable Long userId, int page, int count,
                                 @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count);
        return userRepository
                .findByUserId(userId)
                .map(user -> user.getFollowers(viewerId, pageable))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}/followee", method = RequestMethod.GET)
    public ResultVO getFollowees(@PathVariable Long userId, int page, int count,
                                 @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count);

        return userRepository
                .findByUserId(userId)
                .map(user -> user.getFollowees(viewerId, pageable))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}/clubs", method = RequestMethod.GET)
    public ResultVO getClubs(@PathVariable Long userId, int page, int count) {
        Pageable pageable = new PageRequest(page, count);
        return userRepository
                .findByUserId(userId)
                .map(user -> user.getClubs(pageable))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}/manageClubs",method = RequestMethod.GET)
    public ResultVO getManageClubs(@PathVariable Long userId) {
        return userRepository
                .findByUserId(userId)
                .map(User::getManageClubs)
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}/posts", method = RequestMethod.GET)
    public ResultVO getPosts(@PathVariable Long userId, int page, int count,
                             @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count);
        return userRepository
                .findByUserId(userId)
                .map(user -> user.getUserPosts(viewerId, pageable))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}/comments", method = RequestMethod.GET)
    public ResultVO getComments(@PathVariable Long userId, int page, int count,
                                @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count);
        return userRepository
                .findByUserId(userId)
                .map(user -> user.getUserComments(viewerId, pageable))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}/events", method = RequestMethod.GET)
    public ResultVO getEvents(@PathVariable Long userId, int page, int count) {
        Pageable pageable = new PageRequest(page, count);
        return userRepository
                .findByUserId(userId)
                .map(user -> user.getEvents(pageable))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }

    @RequestMapping(value = "/{userId}/likes/posts", method = RequestMethod.GET)
    public ResultVO getLikePosts(@PathVariable Long userId, int page, int count,
                                 @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count);
        return userRepository
                .findByUserId(userId)
                .map(user -> user.getLikePosts(viewerId, pageable))
                .map(ResultVO::new)
                .orElse(ResultVO.USER_NOT_FOUND);
    }


    /**
     * 修改密码
     */
    @RequestMapping(value = "/setPassword", method = RequestMethod.POST)
    @Transactional
    public ResultVO setPassword(String oldPassword, String newPassword,
                                @RequestHeader(value = "X-Consumer-Username") Long userId) {
        return userRepository
                .findByUserId(userId)
                .flatMap(user -> user.setPassword(oldPassword, newPassword))
                .map(User::getUserInfoTokenVO)
                .map(ResultVO::new)
                .orElse(ResultVO.PASSWORD_ERROR);
    }

    /**
     * 绑定手机号
     */
    @RequestMapping(value = "/bind/phone", method = RequestMethod.POST)
    @Transactional
    public ResultVO bindPhone(String secureToken, String phone,
                              @RequestHeader(value = "X-Consumer-Username") Long userId) {
        if (userService.checkSecureToken(secureToken, phone)) {
            return userRepository
                    .findByUserId(userId)
                    .map(user -> {
                        user.setPhone(phone, true);
                        return user.save();
                    })
                    .map(ResultVO::new).orElse(ResultVO.PHONE_EXIST);
        } else {
            return ResultVO.SECURE_TOKEN_ERROR;
        }
    }

    @RequestMapping(value = "/recommend", method = RequestMethod.GET)
    public ResultVO getUserRecommend(Integer page, Integer count,
                                     @RequestHeader(value = "X-Consumer-Username", defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count, Sort.Direction.ASC, "pos");
        return new ResultVO<>(userService.getRecommends(pageable, viewerId));
    }
    /**
     * 用户管理
     */
    @Autowired
    EntityManagerFactory emf = null;
    @RequestMapping( value = "/findUserListByOther", method = RequestMethod.GET) 
    public ResultVO findUserListByOther(Integer page,Integer count,Long clubId){
    	Pageable pageable = new PageRequest(page,count);

        EntityManager em = emf.createEntityManager();
        if(page == 1){
            page = 0;
        }else{
            page= (page-1)*10;
        }
        StringBuffer sb = new StringBuffer();
        sb.append(" SELECT cm.clubId,u.userId,u.nickname,u.background,u.title,u.province, ");
        sb.append(" IFNULL(p.postCount,0) postCount,IFNULL(f.followeCount,0) followeCount, ");
        sb.append(" IFNULL(e.equipCount,0) equipCount, IFNULL(m.numberCount,0) numberCount FROM userinfo u  LEFT JOIN clubmember cm ON u.userId = cm.userId ");
        sb.append(" LEFT JOIN( SELECT p.userId,COUNT(*) postCount FROM userpost p)p ON u.userId = p.userId ");
        sb.append(" LEFT JOIN( SELECT COUNT(*) numberCount,m.userId FROM clubeventmember m )m ON m.userId = u.userId ");
        sb.append(" LEFT JOIN( SELECT COUNT(*) followeCount,followerId FROM UserFollow)f ON f.followerId = u.userId ");
        sb.append(" LEFT JOIN( SELECT COUNT(*) equipCount,e.userId from UserEquip e)e ON e.userId = u.userId ");
        sb.append(" WHERE cm.clubId = "+clubId+" ORDER BY u.userId LIMIT "+page+","+count+"");

        Query query = em.createNativeQuery(sb.toString());

        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List list = query.getResultList();
        
        StringBuffer sbSum = new StringBuffer();
        sbSum.append(" SELECT cm.clubId,u.userId,u.nickname,u.background,u.title,u.province, ");
        sbSum.append(" IFNULL(p.postCount,0) postCount,IFNULL(f.followeCount,0) followeCount, ");
        sbSum.append(" IFNULL(e.equipCount,0) equipCount, IFNULL(m.numberCount,0) numberCount FROM userinfo u  LEFT JOIN clubmember cm ON u.userId = cm.userId ");
        sbSum.append(" LEFT JOIN( SELECT p.userId,COUNT(*) postCount FROM userpost p)p ON u.userId = p.userId ");
        sbSum.append(" LEFT JOIN( SELECT COUNT(*) numberCount,m.userId FROM clubeventmember m )m ON m.userId = u.userId ");
        sbSum.append(" LEFT JOIN( SELECT COUNT(*) followeCount,followerId FROM UserFollow)f ON f.followerId = u.userId ");
        sbSum.append(" LEFT JOIN( SELECT COUNT(*) equipCount,e.userId from UserEquip e)e ON e.userId = u.userId ");
        sbSum.append(" WHERE cm.clubId = "+clubId+" ORDER BY u.userId ");

        Query querySum = em.createNativeQuery(sbSum.toString());

        querySum.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List listSum = querySum.getResultList();
        
        Map<String,Object> map = new HashMap<String, Object>();
        
        map.put("userList", list);
        map.put("count", listSum.size());
        
        return new ResultVO<>(map);
    }
    /**
     * 修改权限配置
     * @return
     */
    @RequestMapping("/updateCludMenber")
    @Transactional
    public ResultVO joinClub( String clubId,String userId) {
        Map<String, Boolean> result = new HashMap<>();
        Long userIds = Long.parseLong(userId);
        Long clubIds = Long.parseLong(clubId);
        if (userRepository
                .findByUserId(userIds)
                .map(user -> user.joinClub(clubIds))
                .orElse(false)) {
            result.put("success", true);
            return new ResultVO<>(result);
        } else {
            return ResultVO.JOIN_ERROR;
        }
    }

    /**
     * 移交主理人
     * @return
     */
    @RequestMapping("/updateCludAdmin")
    @Transactional
    public ResultVO updateCludAdmin( String clubId,String userId) {
        Long userIds = Long.parseLong(userId);
        Long clubIds = Long.parseLong(clubId);
        Map<String, Boolean> result = new HashMap<>();
        if (userRepository
                .findByUserId(userIds)
                .map(user -> user.founderClub(clubIds))
                .orElse(false)) {
            result.put("success", true);
            return new ResultVO<>(result);
        } else {
            return ResultVO.JOIN_ERROR;
        }
    }
    /**
     * 开除
     * @return
     */
    @RequestMapping("/deleteUser")
    @Transactional
    public ResultVO deleteUser( String clubId,String userId) {
        Long userIds = Long.parseLong(userId);
        Long clubIds = Long.parseLong(clubId);
        Map<String, Boolean> result = new HashMap<>();
        if (userRepository
                .findByUserId(userIds)
                .map(user -> user.leaveClub(clubIds))
                .orElse(false)) {
            result.put("success", true);
            return new ResultVO<>(result);
        } else {
            return ResultVO.JOIN_ERROR;
        }
    }
}
